﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Moq;
using NHibernate;
using NHibernate.Identity;
using NHibernate.Identity.Internal;
using NUnit.Framework;

namespace NHibernateIdentity.Tests.Stores
{
    [TestFixture]
    public class RoleStoreTests
    {
        private Mock<IEntityStore<IdentityRole>> _mockRoleStore;
        private Mock<ISession>  _sessionMock;
        private RoleStore<IdentityRole> _roleStore;

        private List<IdentityRole> _roles;
        
        [TestFixtureSetUp]
        public void Setup()
        {
            // Create instance
            _mockRoleStore = new Mock<IEntityStore<IdentityRole>>();
            _sessionMock = new Mock<ISession>();

            _roles = new List<IdentityRole>
            {
                new IdentityRole("Test1"),
                new IdentityRole("Test2"),
                new IdentityRole("Test3"),
                new IdentityRole("Test4")
            };

            // Setup
            _mockRoleStore.Setup(s => s.Records())
                .Returns(Task.FromResult(_roles.AsQueryable()));

            // Create instance
            _roleStore = new RoleStore<IdentityRole>(_mockRoleStore.Object);
        }

        [Test]
        public void SessionCtor()
        {
            // Setup
            _roleStore = new RoleStore<IdentityRole>(_sessionMock.Object);

            // Assert
            Assert.IsNotNull(_roleStore.Session);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SessionCtorException()
        {
            // Perform
            _roleStore = new RoleStore<IdentityRole>((ISession) null);
        }

        [Test]
        public async void CanCreateRole()
        {
            // Perform
            var role = new IdentityRole("Test5");
            await _roleStore.CreateAsync(role);

            // Assert
            _mockRoleStore.Verify(v => v.Save(role), Times.Once);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public async void CanCreateRoleException()
        {
            await _roleStore.CreateAsync(null);
        }

        [Test]
        public async void CanUpdateRole()
        {
            // Perform
            _roles[0].Name = "Test6";
            await _roleStore.UpdateAsync(_roles[0]);

            // Assert
            _mockRoleStore.Verify(v => v.Save(_roles[0]), Times.Once);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public async void CanUpdateRoleException()
        {
            await _roleStore.UpdateAsync(null);
        }

        [Test]
        public async void CanDeleteRole()
        {
            // Perform
            await _roleStore.DeleteAsync(_roles[0]);

            // Assert
            _mockRoleStore.Verify(v => v.Delete(_roles[0]), Times.Once);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public async void CanDeleteRoleException()
        {
            await _roleStore.DeleteAsync(null);
        }

        [Test]
        public async void CanFindRoleById()
        {
            // Perform
            var role = await _roleStore.FindByIdAsync(_roles[2].Id);

            // Assert
            Assert.AreEqual(role.Name, _roles[2].Name);
        }

        [Test]
        public async void CanFindRoleByName()
        {
            // Perform
            var role = await _roleStore.FindByNameAsync(_roles[2].Name);

            // Assert
            Assert.AreEqual(role.Id, _roles[2].Id);
        }

        [Test]
        [ExpectedException(typeof(ObjectDisposedException))]
        public async void ThrowDisposed()
        {
            // Perform
            _roleStore.Dispose();
            await _roleStore.FindByNameAsync(_roles[2].Name);
        }

        [Test]
        [ExpectedException(typeof(ObjectDisposedException))]
        public async void ThrowDisposedWithSession()
        {
            // Setup
            _roleStore = new RoleStore<IdentityRole>(_sessionMock.Object);

            // Assert
            Assert.IsNotNull(_roleStore.Session);

            // Perform
            _roleStore.Dispose();
            await _roleStore.FindByNameAsync(_roles[2].Name);
        }
    }
}
